
/**
 * Date:2019年9月4日上午11:07:26
 * Copyright (c) 2019, www.bwbroad.com All Rights Reserved.
 *
*/

package com.app.common.config;

import java.io.Serializable;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Description: redis配置 <br/>
 * Date: 2019年9月4日 上午11:07:26 <br/>
 * 
 * @author xuejianxin
 */
@ConditionalOnProperty(value = "spring.redis.host", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
	// 参考文档 https://www.cnblogs.com/a565810497/p/10937477.html
	@Bean
	public <V extends Serializable> RedisTemplate<String, V> redisTemplate(RedisConnectionFactory factory) {
		RedisTemplate<String, V> template = new RedisTemplate<String, V>();
		template.setConnectionFactory(factory);
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
				Object.class);
		// 如果数据保存的不正常 请注意以下代码设置
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY);
		// 是否在json中保留类型信息
		// om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
		// ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);

		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		template.setKeySerializer(stringRedisSerializer);
		template.setValueSerializer(jackson2JsonRedisSerializer);
		template.setHashKeySerializer(stringRedisSerializer);
		template.setHashValueSerializer(jackson2JsonRedisSerializer);

		template.afterPropertiesSet();
		return template;
	}

	@Bean
	public CacheManager cacheManager(RedisTemplate<String, Object> template) {
		RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder
				.fromConnectionFactory(template.getConnectionFactory())
				// 默认缓存配置永久缓存
				.cacheDefaults(getCacheConfigWithTtl(template, null))
				// 其他缓存
				.withInitialCacheConfigurations(initialCacheConfigurations(template))
				// 配置同步修改或删除 put/evict
				.transactionAware().build();

		return redisCacheManager;
	}

	private Map<String, RedisCacheConfiguration> initialCacheConfigurations(RedisTemplate<String, Object> template) {
		Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
		redisCacheConfigurationMap.put("day1", this.getCacheConfigWithTtl(template, Duration.ofDays(1)));
		redisCacheConfigurationMap.put("hours1", this.getCacheConfigWithTtl(template, Duration.ofHours(1)));
		redisCacheConfigurationMap.put("minute10", this.getCacheConfigWithTtl(template, Duration.ofMinutes(10)));
		redisCacheConfigurationMap.put("minute1", this.getCacheConfigWithTtl(template, Duration.ofMinutes(1)));
		return redisCacheConfigurationMap;
	}

	private RedisCacheConfiguration getCacheConfigWithTtl(RedisTemplate<String, Object> template, Duration ttl) {

		RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
				// 设置key为String
				.serializeKeysWith(
						RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))
				// 设置value 为自动转Json的Object
				.serializeValuesWith(
						RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))
				// 不缓存null
				.disableCachingNullValues();
		if (null != ttl) {
			cacheConfiguration.entryTtl(ttl);
		}
		return cacheConfiguration;

	}

}
